/***************************************************************************
    File                 : AbstractSimpleFilter.cpp
    Project              : AlphaPlot
    --------------------------------------------------------------------
    Copyright            : (C) 2007-2009 by Knut Franke, Tilman Benkert
    Email (use @ for *)  : knut.franke*gmx.de, thzs*gmx.net
    Description          : Simplified filter interface for filters with
                           only one output port.

 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *  This program is free software; you can redistribute it and/or modify   *
 *  it under the terms of the GNU General Public License as published by   *
 *  the Free Software Foundation; either version 2 of the License, or      *
 *  (at your option) any later version.                                    *
 *                                                                         *
 *  This program is distributed in the hope that it will be useful,        *
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of         *
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          *
 *  GNU General Public License for more details.                           *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the Free Software           *
 *   Foundation, Inc., 51 Franklin Street, Fifth Floor,                    *
 *   Boston, MA  02110-1301  USA                                           *
 *                                                                         *
 ***************************************************************************/

#include "AbstractSimpleFilter.h"
#include <QtDebug>

// TODO: should simple filters have a name argument?
AbstractSimpleFilter::AbstractSimpleFilter()
    : AbstractFilter("SimpleFilter"),
      d_output_column(new SimpleFilterColumn(this)) {
  addChild(d_output_column);
}

void AbstractSimpleFilter::clearMasks() {
  emit d_output_column->maskingAboutToChange(d_output_column);
  d_masking.clear();
  emit d_output_column->maskingChanged(d_output_column);
}

void AbstractSimpleFilter::setMasked(Interval<int> i, bool mask) {
  emit d_output_column->maskingAboutToChange(d_output_column);
  d_masking.setValue(i, mask);
  emit d_output_column->maskingChanged(d_output_column);
}

void AbstractSimpleFilter::inputPlotDesignationAboutToChange(
    const AbstractColumn *) {
  emit d_output_column->plotDesignationAboutToChange(d_output_column);
}

void AbstractSimpleFilter::inputPlotDesignationChanged(const AbstractColumn *) {
  emit d_output_column->plotDesignationChanged(d_output_column);
}

void AbstractSimpleFilter::inputModeAboutToChange(const AbstractColumn *) {
  emit d_output_column->dataAboutToChange(d_output_column);
}

void AbstractSimpleFilter::inputModeChanged(const AbstractColumn *) {
  emit d_output_column->dataChanged(d_output_column);
}

void AbstractSimpleFilter::inputDataAboutToChange(const AbstractColumn *) {
  emit d_output_column->dataAboutToChange(d_output_column);
}

void AbstractSimpleFilter::inputDataChanged(const AbstractColumn *) {
  emit d_output_column->dataChanged(d_output_column);
}

void AbstractSimpleFilter::inputRowsAboutToBeInserted(
    const AbstractColumn *source, int before, int count) {
  Q_UNUSED(source);
  Q_UNUSED(count);
  foreach (Interval<int> output_range,
           dependentRows(Interval<int>(before, before)))
    emit d_output_column->rowsAboutToBeInserted(
        d_output_column, output_range.start(), output_range.size());
}

void AbstractSimpleFilter::inputRowsInserted(const AbstractColumn *source,
                                             int before, int count) {
  Q_UNUSED(source);
  Q_UNUSED(count);
  foreach (Interval<int> output_range,
           dependentRows(Interval<int>(before, before)))
    emit d_output_column->rowsInserted(d_output_column, output_range.start(),
                                       output_range.size());
}

void AbstractSimpleFilter::inputRowsAboutToBeRemoved(
    const AbstractColumn *source, int first, int count) {
  Q_UNUSED(source);
  foreach (Interval<int> output_range,
           dependentRows(Interval<int>(first, first + count - 1)))
    emit d_output_column->rowsAboutToBeRemoved(
        d_output_column, output_range.start(), output_range.size());
}

void AbstractSimpleFilter::inputRowsRemoved(const AbstractColumn *source,
                                            int first, int count) {
  Q_UNUSED(source);
  foreach (Interval<int> output_range,
           dependentRows(Interval<int>(first, first + count - 1)))
    emit d_output_column->rowsRemoved(d_output_column, output_range.start(),
                                      output_range.size());
}

AbstractColumn *AbstractSimpleFilter::output(int port) {
  return port == 0 ? static_cast<AbstractColumn *>(d_output_column) : 0;
}

const AbstractColumn *AbstractSimpleFilter::output(int port) const {
  return port == 0 ? static_cast<const AbstractColumn *>(d_output_column) : 0;
}

void AbstractSimpleFilter::save(QXmlStreamWriter *writer) const {
  writer->writeStartElement("simple_filter");
  writeBasicAttributes(writer);
  writeExtraAttributes(writer);
  writer->writeAttribute("filter_name", metaObject()->className());
  writeCommentElement(writer);
  writer->writeEndElement();
}

bool AbstractSimpleFilter::load(XmlStreamReader *reader) {
  if (reader->isStartElement() && reader->name() == "simple_filter") {
    if (!readBasicAttributes(reader)) return false;

    QXmlStreamAttributes attribs = reader->attributes();
    QString str =
        attribs.value(reader->namespaceUri().toString(), "filter_name")
            .toString();
    if (str != metaObject()->className()) {
      reader->raiseError(tr("incompatible filter type"));
      return false;
    }

    // read child elements
    while (!reader->atEnd()) {
      reader->readNext();

      if (reader->isEndElement()) break;

      if (reader->isStartElement()) {
        if (reader->name() == "comment") {
          if (!readCommentElement(reader)) return false;
        } else  // unknown element
        {
          reader->raiseWarning(
              tr("unknown element '%1'").arg(reader->name().toString()));
          if (!reader->skipToEndElement()) return false;
        }
      }
    }
  } else
    reader->raiseError(tr("no simple filter element found"));

  return !reader->hasError();
}
